package com.gitee.zycra.future.job.web.aspect;

import com.gitee.zycra.future.job.common.bo.CommonResult;
import com.gitee.zycra.future.job.common.config.EncryptConfig;
import com.gitee.zycra.future.job.common.util.AESUtil;
import com.gitee.zycra.future.job.common.util.DateUtil;
import com.gitee.zycra.future.job.common.util.UserInfoUtil;
import com.gitee.zycra.future.job.web.annotation.AuthCheck;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * @author zycra
 */
@Slf4j
@Aspect
@Component
public class AuthCheckAspect {

    private static final int TOKEN_LENGTH = 4;

    private static final int USER_ID_OFFSET = 0;

    private static final int AUTH_OFFSET = 1;

    private static final int USERNAME_OFFSET = 2;

    private static final int EXPIRE_TIME_OFFSET = 3;

    private static final String ALL_AUTH = "0";
    @Autowired
    private EncryptConfig encryptConfig;

    @Pointcut("@annotation(com.gitee.zycra.future.job.web.annotation.AuthCheck)")
    public void pointcut() {
        // 定义切点
    }

    @Around("pointcut() && @annotation(authCheck)")
    public Object around(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        String[] value = authCheck.value();
        if (requestAttributes == null || value == null || value.length == 0) {
            return joinPoint.proceed();
        }
        Set<String> authSet = new HashSet<>(Arrays.asList(value));
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String token = request.getHeader("token");
        String decryptToken = AESUtil.decrypt(token, encryptConfig.getTokenKey());
        if (decryptToken == null) {
            return CommonResult.failed("未登录");
        }
        String[] userInfo = decryptToken.split(",");
        if (userInfo.length != TOKEN_LENGTH) {
            return CommonResult.failed("非法token");
        }
        String auth = userInfo[AUTH_OFFSET];
        if (ALL_AUTH.equals(auth)) {
            return doProcess(joinPoint, userInfo);
        }
        long expireTime = Long.parseLong(userInfo[EXPIRE_TIME_OFFSET]);
        if (DateUtil.getNowTimestamp() > expireTime) {
            return CommonResult.failed("token过期");
        }
        if (!authSet.contains(auth)) {
            return CommonResult.failed("无权限");
        }
        return doProcess(joinPoint, userInfo);
    }

    private Object doProcess(ProceedingJoinPoint joinPoint, String[] userInfo) throws Throwable {
        Long userId = Long.valueOf(userInfo[USER_ID_OFFSET]);
        String username = userInfo[USERNAME_OFFSET];
        try {
            UserInfoUtil.setValue(userId, username);
            return joinPoint.proceed();
        } finally {
            UserInfoUtil.removeValue();
        }
    }
}
